﻿using System;
using System.Linq;
using System.Text;
using System.Web.UI;
using NativeCode.Core.Data;
using NativeCode.Core.Data.LinqKit;
using NativeCode.Core.Extensions;
using NativeCode.Web.Controls.Filters;
using SampleWebAppData;

namespace SampleWebApp
{
	public partial class Default : Page
	{
		protected AuthenticationDataContext DataContext { get; private set; }

		protected override void OnInit(EventArgs e)
		{
			// The page should always be responsible for creating the data context unless you
			// are relying heavily on DataLoadOptions. I ain't adapting nothin'! I know what
			// I need and it's not more IEnumerables!
			DataContext = new AuthenticationDataContext();

			SampleDataCheckBoxSelector.Bind(query => Customer.Samples(), () => Customer.Samples().Count());

			SampleDataQueryFilterBar.Bind(query => Customer.Samples(), () => Customer.Samples().Count());
			SampleDataQueryFilterBar.OnFiltersCleared += HandleSampleDataQbeFilterBarFiltersCleared;

			// The annoyiing call to AsExpandable is so that LINQ-to-Entities can participate and use our
			// InvocationExpresions. Calling AsExpandable is not needed in LINQ-to-SQL.
			LoginsQueryFilterBar.Bind(query => DataContext.LoginSet.AsExpandable(), () => DataContext.LoginSet.Count());
			LoginsQueryFilterBar.OnFiltersCleared += HandleLoginsQbeFilterBarFiltersCleared;

			#region Debugging

			OutputLiteral.Text = string.Empty;

			OutputLiteral.Text += string.Format("<div><em>Available filters ({0}):</em></div>", SampleDataQueryFilterBar.AvailableFilters.Count);
			foreach (QueryFilter filter in SampleDataQueryFilterBar.AvailableFilters
				.OrderBy(av => av.FilterType.Name)
				.ThenBy(av => av.PropertyName)
				.ThenBy(av => av.FilterOperator))
			{
				OutputLiteral.Text += filter.ToHtmlString();
			}

			OutputLiteral.Text += string.Format("<div><em>All filters ({0}):</em></div>", FilterableTypesRegistry.RegisteredFilters.Count());
			foreach (QueryFilter filter in FilterableTypesRegistry.RegisteredFilters
				.OrderBy(av => av.FilterType.Name)
				.ThenBy(av => av.PropertyName)
				.ThenBy(av => av.FilterOperator))

			{
				OutputLiteral.Text += filter.ToHtmlString();
			}

			#endregion

			base.OnInit(e);
		}

		/// <summary>
		/// We are creating FilterBarItems in code. Realistically, this will never happen as it will be
		/// the user controlling what FilterBarItems are created.
		/// </summary>
		/// <param name="e"></param>
		protected override void OnLoad(EventArgs e)
		{
			if (!IsPostBack)
			{
				SampleDataCheckBoxSelector.DataBind();

				SampleDataQueryFilterBar.FilterBarItems.AddRange(new[]
				{
					new QueryFilterBarItem(typeof (Customer), "FullName", QueryFilterOperator.Contains, "a", QueryFilterConjunction.None),
					new QueryFilterBarItem(typeof (Customer), "FullName", QueryFilterOperator.Contains, "i", QueryFilterConjunction.And),
				});
				SampleDataQueryFilterBar.DataBind();

				LoginsQueryFilterBar.FilterBarItems.AddRange(new[]
				{
					new QueryFilterBarItem(typeof (Login), "UserName", QueryFilterOperator.Contains, "o", QueryFilterConjunction.None),
					new QueryFilterBarItem(typeof (Login), "UserName", QueryFilterOperator.Equals, "R2-D2", QueryFilterConjunction.Or),
				});
				LoginsQueryFilterBar.DataBind();
			}

			base.OnLoad(e);
		}

		protected override void OnPreRenderComplete(EventArgs e)
		{
			#region Debugging

			StringBuilder sb = new StringBuilder();

			// Customers

			IQueryable<Customer> customerQuery = SampleDataQueryFilterBar.ApplyFilterToQueryable(Customer.Samples());

			sb.AppendLine("<div class=\"query-results\"><div><em>Query results:</em></div><table class=\"debug\">");
			foreach (Customer customer in customerQuery)
			{
				sb.Append(customer.ToHtmlRow());
			}
			sb.AppendLine("</table></div>");
			sb.AppendFormat("<div>EXPRESSION: {0}</div>", customerQuery.Expression);

			// Logins

			IQueryable<Login> loginQuery = LoginsQueryFilterBar.ApplyFilterToQueryable(DataContext.LoginSet.AsExpandable());

			sb.AppendLine("<div class=\"query-results\"><div><em>Query results:</em></div><table class=\"debug\">");
			foreach (Login login in loginQuery)
			{
				sb.Append(login.ToHtmlRow());
			}
			sb.AppendLine("</table></div>");
			sb.AppendFormat("<div>SQL: {0}</div>", loginQuery);
			sb.AppendFormat("<div>EXPRESSION: {0}</div>", loginQuery.Expression);

			QueryOutputLiteral.Text = sb.ToString();

			#endregion

			base.OnPreRenderComplete(e);

			// Get rid of the DataContext like a good developer should! We do it on pre-render
			// since at this point, all data should be available and retrieved.
			if (DataContext != null)
			{
				DataContext.Dispose();
				DataContext = null;
			}
		}

		/// <summary>
		/// Rebind the filter bar when items are cleared. Also clear any associated controls at
		/// this point to keep things in sync.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void HandleSampleDataQbeFilterBarFiltersCleared(object sender, EventArgs e)
		{
			SampleDataCheckBoxSelector.DataBind();
			SampleDataQueryFilterBar.DataBind();
		}

		/// <summary>
		/// Rebind the filter bar when items are cleared.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void HandleLoginsQbeFilterBarFiltersCleared(object sender, EventArgs e)
		{
			LoginsQueryFilterBar.DataBind();
		}

		protected void HandleCheckStuffButton_Click(object sender, EventArgs e)
		{
			SampleDataCheckBoxSelector.DataBind();
			SampleDataQueryFilterBar.DataBind();
			LoginsQueryFilterBar.DataBind();
		}
	}
}